#include <algorithm>

#include "Mode.h"

std::string lower(const std::string &str)
{
    std::string low = str;
    std::transform(str.begin(), str.end(), low.begin(), ::tolower);
    return low;
}

Dimension string2Dimension(const std::string &str)
{
    auto dim = lower(str);
    if (dim == "one")
        return Dimension::One;
    else if (dim == "two")
        return Dimension::Two;
    else
        return Dimension::One;
}

#define ENUM2STRING(enu) \
    case enu:            \
        return #enu;

std::string Dimension2string(const Dimension &dimension)
{
    switch (dimension)
    {
        ENUM2STRING(One);
        ENUM2STRING(Two);
    default:
        break;
    }
    return std::string();
}

BoundType string2BoundType(const std::string &str)
{
    auto boundType = lower(str);
    if (boundType == "dirichlet")
        return BoundType::Dirichlet;
    else if (boundType == "neumann")
        return BoundType::Neumann;
    else
        return BoundType::Dirichlet;
}

std::string BoundType2string(const BoundType &boundType)
{
    switch (boundType)
    {
        ENUM2STRING(Dirichlet);
        ENUM2STRING(Neumann);
    default:
        break;
    }
    return std::string();
}

// BoundName string2BoundName(const std::string& str)
// {
//     auto boundName = lower(str);
//     if (boundName == "up")
//         return BoundName::Up;
//     else if (boundName == "right")
//         return BoundName::Right;
//     else if (boundName == "down")
//         return BoundName::Down;
//     else if (boundName == "left")
//         return BoundName::Left;
//     else
//         return BoundName::Up;
// }

CycleChoice string2CycleChoice(const std::string &str)
{
    auto cycleChoice = lower(str);
    if (cycleChoice == "vcycle")
        return CycleChoice::Vcycle;
    else if (cycleChoice == "fmg")
        return CycleChoice::FMG;
    else
        return CycleChoice::Vcycle;
}

std::string CycleChoice2string(const CycleChoice &cycleChoice)
{
    switch (cycleChoice)
    {
        ENUM2STRING(Vcycle);
        ENUM2STRING(FMG);
    default:
        break;
    }
    return std::string();
}

Operators::Restriction Operators::string2Restriction(const std::string &str)
{
    auto rtype = lower(str);
    if (rtype == "injection")
        return Operators::Restriction::Injection;
    else if (rtype == "fullWeighting")
        return Operators::Restriction::FullWeighting;
    else
        return Operators::Restriction::Injection;
}

std::string Operators::Restriction2string(const Restriction &restriction)
{
    switch (restriction)
    {
        ENUM2STRING(Injection);
        ENUM2STRING(FullWeighting);
    default:
        break;
    }
    return std::string();
}

Operators::Interpolation Operators::string2Interpolation(const std::string &str)
{
    auto itype = lower(str);
    if (itype == "linear")
        return Operators::Interpolation::Linear;
    else if (itype == "qudratic")
        return Operators::Interpolation::Qudratic;
    else
        return Operators::Interpolation::Linear;
}

std::string Operators::Interpolation2string(const Interpolation &interpolation)
{
    switch (interpolation)
    {
        ENUM2STRING(Linear);
        ENUM2STRING(Qudratic);
    default:
        break;
    }
    return std::string();
}
